package com.itheima.springbootwebtest.aspect;

import com.itheima.springbootwebtest.annotation.AutoLogAnnotation;
import com.itheima.springbootwebtest.context.BaseContext;
import com.itheima.springbootwebtest.mapper.LogMapper;
import com.itheima.springbootwebtest.pojo.OperationLog;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;

/**
 * 面向切面编程
 *
 * @Author mr.luo
 * @Date 14 4月 2025 15:56
 */
@Aspect
@Component
@Slf4j
public class AutoLogAspect {
    @Autowired
    private LogMapper logMapper;
    //切入点
    @Pointcut("execution(* com.itheima.springbootwebtest.mapper.*.*(..)) && @annotation(com.itheima.springbootwebtest.annotation.AutoLogAnnotation) ")
    public void pt() {
    }

    //通知类型
    @Around("pt()")
    public Object around(ProceedingJoinPoint pj) throws Throwable {
        log.info("环绕通知开始");
        Long startTime = System.currentTimeMillis();
        Object result = pj.proceed();
        Long endTime = System.currentTimeMillis();
        OperationLog operationLog = new OperationLog();
        // 获取当前登录用户信息
        operationLog.setOperateEmpId(BaseContext.getThreadLocal());
        operationLog.setOperateTime(LocalDateTime.now());
        operationLog.setClassName(pj.getTarget().getClass().getName());
        operationLog.setMethodName(pj.getSignature().getName());
        operationLog.setMethodParams(Arrays.toString(pj.getArgs()));
        if (result != null ) {
            operationLog.setReturnValue(result.toString());
        } else {
            operationLog.setReturnValue("无返回值");
        }
        operationLog.setCostTime((endTime - startTime)); // 耗时 单位毫秒
        MethodSignature signature = (MethodSignature) pj.getSignature();
        AutoLogAnnotation annotation = signature.getMethod().getAnnotation(AutoLogAnnotation.class);
        operationLog.setOperationType(annotation.value().name());
        logMapper.addLog(operationLog);


        Object[] arg = pj.getArgs();
        LocalDateTime now = LocalDateTime.now();
        if (arg != null && arg.length > 0 && !(arg[0] instanceof List)) {
            if (operationLog.getOperationType().equals("Insert") ) {
                //通过反射为第一个参数赋值
                arg[0].getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class).invoke(arg[0], now);
                arg[0].getClass().getDeclaredMethod("setCreateTime", LocalDateTime.class).invoke(arg[0], now);
                //暴力获取私有属性
            } else if (operationLog.getOperationType().equals("Update")) {
                arg[0].getClass().getDeclaredMethod("setUpdateTime", LocalDateTime.class).invoke(arg[0], now);
            }
            log.info(Arrays.toString(arg));
        }
        log.info("环绕通知结束");
        return result;
    }
}
